package com.c2b.algorithm.leetcode.base;

/**
 * <a href="https://leetcode.cn/problems/koko-eating-bananas/">爱吃香蕉的珂珂(Koko Eating Bananas)</a>
 * <p>珂珂喜欢吃香蕉。这里有 n 堆香蕉，第 i 堆中有 piles[i] 根香蕉。警卫已经离开了，将在 h 小时后回来。</p>
 * <p>珂珂可以决定她吃香蕉的速度 k （单位：根/小时）。每个小时，她将会选择一堆香蕉，从中吃掉 k 根。如果这堆香蕉少于 k 根，她将吃掉这堆的所有香蕉，然后这一小时内不会再吃更多的香蕉。  </p>
 * <p>珂珂喜欢慢慢吃，但仍然想在警卫回来前吃掉所有的香蕉。</p>
 * <p>返回她可以在 h 小时内吃掉所有香蕉的最小速度 k（k 为整数）。</p>
 *
 * <p>
 * <b>示例：</b>
 * <pre>
 * 示例 1：
 *      输入：piles = [3,6,7,11], h = 8
 *      输出：4
 *
 * 示例 2：
 *      输入：piles = [30,11,23,4,20], h = 5
 *      输出：30
 *
 * 示例 3：
 *      输入：piles = [30,11,23,4,20], h = 6
 *      输出：23
 * </pre>
 * </p>
 *
 * <p>
 * <b>提示：</b>
 *  <ul>
 *      <li>1 <= piles.length <= 10^4</li>
 *      <li>piles.length <= h <= 10^9</li>
 *      <li>1 <= piles[i] <= 10^9</li>
 *  </ul>
 * </p>
 *
 * @author c2b
 * @since 2023/11/14 16:31
 */
public class LC0875KokoEatingBananas_M {

    static class Solution {
        public int minEatingSpeed(int[] piles, int h) {
            int maxValue = 1;
            for (int pile : piles) {
                maxValue = Math.max(maxValue, pile);
            }
            // 速度最小为1，此时耗时最长
            int left = 1;
            // 速度最大为一小时吃的最大堆的香蕉数，此时耗时最短
            int right = maxValue;
            while (left < right) {
                int mid = left + ((right - left) >> 1);
                // 计算以 mid速度吃完所有的香蕉所需要的时间
                int totalTime = calculateSumTime(piles, mid);
                if (totalTime > h) {
                    // 如果所需时间超过规定的时间，说明速度太慢，需要加快速度。下一轮的速度区间为[mid+1,right]
                    left = mid + 1;
                } else {
                    // 如果所需小于等于超过规定的时间，说明速度太快，尝试降低速度。下一轮的速度区间为[left,mid]
                    right = mid;
                }
            }
            return left;
        }

        /**
         * 计算以 speed / h吃完所有的香蕉所需要的时间。
         *
         * @return 需要的小时数，向上取整
         */
        private int calculateSumTime(int[] piles, int speed) {
            int sum = 0;
            for (int pile : piles) {
                sum += pile / speed;
                // 向上取整
                if (pile % speed != 0) {
                    sum += 1;
                }
            }
            return sum;
        }
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        //System.out.println(solution.minEatingSpeed(new int[]{3, 6, 7, 11}, 8));
        //System.out.println(solution.minEatingSpeed(new int[]{30, 11, 23, 4, 20}, 5));
        //System.out.println(solution.minEatingSpeed(new int[]{30, 11, 23, 4, 20}, 6));
        System.out.println(solution.minEatingSpeed(new int[]{312884470}, 312884469));
    }
}
